import { App } from "obsidian";
import Heading from "./heading";
import Fuse from "fuse.js";

export default class HeadingTree {

    private _root: Heading = null;

    private __allHeading: Heading[] = null;
    private get _allHeading(): Heading[] {
        if (this.__allHeading === null) this.__allHeading = this._root.getAllHeadings(true);
        return this.__allHeading;
    }

    private _visibleHeadings: Heading[] = null;
    public get visibleHeadings(): Heading[] {
        if (this._visibleHeadings === null) this._visibleHeadings = this._root.getAllHeadings();
        return this._visibleHeadings;
    }

    private __fuse: Fuse<Heading> = null;
    private get _fuse(): Fuse<Heading> {
        if (this.__fuse === null) {
            let options = {
                keys: ['name'],
            };
            this.__fuse = new Fuse(this._allHeading, options);
        }
        return this.__fuse;
    }

    constructor(app: App) {
        this._root = new Heading;

        let file = app.workspace.getActiveFile();
        if (file == null) return;

        let headings = app.metadataCache.getFileCache(file)?.headings;
        if (headings == undefined || headings.length == 0) return;

        let index = this._root;
        let heading: Heading = null;
        for (let it of headings) {
            // 忽略空标题
            if (it.heading == "") continue;

            heading = new Heading(it.heading, it.level, it.position.start.line);

            if (index.level == 0) {
                index.addChild(heading);
                index = heading;
                continue;
            }

            if (heading.level == index.level) {
                index.parent.addChild(heading);
                index = heading;
            }
            else if (heading.level < index.level) {
                let parent = index.backtrackParent(heading.level - 1);
                if (parent == null) continue;
                parent.addChild(heading);
                index = heading;
            }
            else if (heading.level - 1 == index.level) {
                index.addChild(heading);
                index = heading;
            }
            else {
                // 跳级别了，丢弃
            }
        }
    }

    reset() {
        this.__allHeading = null;
        this._visibleHeadings = null;
        this.__fuse = null;
    }

    locateHeading(line: number): Heading {
        if (this._allHeading == null) return null;

        let heading: Heading = null;
        for (let i = 0; i < this._allHeading.length; i++) {
            let it = this._allHeading.at(i);

            if (it.line > line) {
                if (i == 0) heading = it;
                else heading = this._allHeading.at(i - 1);
                break;
            }
            else if (it.line == line) {
                heading = it;
                break;
            }
        }

        if (heading == null) heading = this._allHeading.last();
        return heading;
    }

    search(keyWord: string): Heading[] {
        let fuseResults = this._fuse.search(keyWord);
        let results: Heading[] = [];
        for (let it of fuseResults) results.push(it.item);

        return results;
    }

    setAllExpand(isExpand: boolean) { this._allHeading.forEach(v => v.isExpand = isExpand); }

    /**级别小于等于level的标题展开，其它折叠 */
    setFoldLevel(level: number) { this._allHeading.forEach(v => v.isExpand = v.level <= level); }

}
